﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX;
using System.Drawing;
using System.IO;

namespace EdytorWF.Objects
{
    public class ModelObject : SimpleObject
    {
        private static int counter = 0;

        public Vector3 Rotation { get; set; }
        public Vector3 Scale { get; set; }
        public float Helper { get; set; }

        protected List<CustomVertex.PositionNormalTextured> Vertices;
        protected List<int> Indices;
        protected LightObject[] Lights { get; set; }

        public ModelObject()
        {
            TypeName = "_MODEL_OBJECT";
            Helper = 0.0f;

            Position = new Vector3(0, 0, 0);
            Rotation = new Vector3(0, 0, 0);
            Scale = new Vector3(1, 1, 1);

            Vertices = new List<CustomVertex.PositionNormalTextured>();
            Indices = new List<int>();
            Lights = new LightObject[6]; //Max lights

            ExtendedMaterials.Add(new ExtendedMaterial());
            Materials = new List<Material>();
            Materials.Add(new Material
            {
                Ambient = Color.White,
                Diffuse = Color.White
            });

            MeshFileName = IEngine.EngineInstance.DefaultObjectMeshName; // Set default MeshFile
            TextureFileName = IEngine.EngineInstance.DefaultObjectTextureName; // Set default TextureFile
        }

        public ModelObject(Device dev, Vector3 init_pos, bool isHelper = false)
        {
            Device = dev;
            
            TypeName = "_MODEL_OBJECT";
            ObjectName = String.Format("ModelObject{0}", counter);
            Helper = 0.0f;

            if (!isHelper)
            {
                ++counter;
            }
            
            Position = new Vector3(init_pos.X, init_pos.Y, init_pos.Z);
            Rotation = new Vector3(0, 0, 0);
            Scale = new Vector3(1, 1, 1);

            Vertices = new List<CustomVertex.PositionNormalTextured>();
            Indices = new List<int>();
            Lights = new LightObject[6]; //Max lights

            ExtendedMaterials.Add(new ExtendedMaterial());
            Materials = new List<Material>();
            Materials.Add(new Material
            {
                Ambient = Color.White,
                Diffuse = Color.White
            });

            MeshFileName = IEngine.EngineInstance.DefaultObjectMeshName; // Set default MeshFile
            TextureFileName = IEngine.EngineInstance.DefaultObjectTextureName; // Set default TextureFile

            LoadMesh(MeshFileName);
            LoadTexture(TextureFileName);
        }
 
        public void SetLight(LightObject l_object, int index)
        {
            if (index < Lights.Length)
            {
                Lights[index] = l_object;
            }
        }

        public void SetMeshAttribs(List<CustomVertex.PositionNormalTextured> vertices, List<int> indices)
        {
            Vertices = vertices;
            Indices = indices;

            MyMesh = new Mesh(Indices.Count / 3, Vertices.Count, MeshFlags.Managed | MeshFlags.Use32Bit, CustomVertex.PositionNormalTextured.Format, Device);
            MyMesh.IndexBuffer.SetData(Indices.ToArray(), 0, LockFlags.None);
            MyMesh.VertexBuffer.SetData(Vertices.ToArray(), 0, LockFlags.None);
            MyMesh.ComputeNormals();
            CollisionBox = new Engine.BoundingBox(this);
        }

        public List<CustomVertex.PositionNormalTextured> GetVertices() { return Vertices; }
        public override void ReloadMesh()
        {
            LoadMesh(MeshFileName);
        }

        public override void ReloadTexture()
        {
            if (TextureFileName != "")
            {
                if (Device == null)
                    return;

                if (Textures != null)
                {
                    if (Textures.Count >= 1)
                    {
                        Textures.Clear();
                    }
                    Textures.Add(TextureLoader.FromFile(Device, TextureFileName));
                }
            }
        }

        public override void ReloadObject()
        {
            ReloadMesh();
            ReloadTexture();
        }

        public override void Render()             // Rendering obiektu na device
        {
            if (Device != null && MyMesh != null)
            {
                Device.VertexFormat = MyMesh.VertexFormat;   //Ustalamy Format Vertexów
                for (int i = 0; i < ExtendedMaterials.Count; i++)      //EM.Length zawiera liczbę submeshów danego mesha
                {
                    Device.Material = Materials[i];            //każdy submesh ma inny materiał
                    Device.SetTexture(0, Textures[i]);         //i inną teksturę
                    MyMesh.DrawSubset(i);                        //rendering i-tego submesha
                }
            }
        }

        public override void Render(ref Effect effect, String texture, bool with_lights = true)             // Rendering obiektu na device
        {
            if (Device != null && MyMesh != null)
            {
                Device.VertexFormat = MyMesh.VertexFormat;   //Ustalamy Format Vertexów
                for (int i = 0; i < ExtendedMaterials.Count; i++)      //EM.Length zawiera liczbę submeshów danego mesha
                {
                    if (texture != null)
                    {
                        effect.SetValue(texture, Textures[i]);
                        if (with_lights)
                        {
                            for (uint j = 0; j < 6; ++j)
                            {
                                if (Lights != null && Lights[j] != null)
                                {
                                    effect.SetValue(string.Format("xLightPosition{0}", j), new Vector4(Lights[j].Position.X, Lights[j].Position.Y, Lights[j].Position.Z, 1.0f));
                                    effect.SetValue(string.Format("xLightColor{0}", j), new Vector4(Lights[j].DiffuceColor.R, Lights[j].DiffuceColor.G, Lights[j].DiffuceColor.B, Lights[j].DiffuceColor.A));
                                    effect.SetValue(string.Format("xLightPower{0}", j), Lights[j].DiffucePower);
                                }
                                else
                                {
                                    effect.SetValue(string.Format("xLightPosition{0}", j), new Vector4(0, 0, 0, 1.0f));
                                    effect.SetValue(string.Format("xLightColor{0}", j), new Vector4(0, 0, 0, 0));
                                    effect.SetValue(string.Format("xLightPower{0}", j), 0);
                                }
                            }
                            effect.SetValue("xHelper", Helper);
                        }
                        effect.CommitChanges();
                    }
                    //Device.Material = Materials[i];            //każdy submesh ma inny materiał
                    //Device.SetTexture(0, Textures[i]);         //i inną teksturę
                    MyMesh.DrawSubset(i);                        //rendering i-tego submesha
                }
            }
        }

        public override void LoadTexture(string FileName)
        {
            TextureFileName = FileName;

            if (Device == null)
                return;

            if (Textures != null)
            {
                Textures.Add(TextureLoader.FromFile(Device, TextureFileName));
            }
        }

        public override void LoadMesh(String type)
        {
            if (Vertices == null | Indices == null | Device == null)
                return;

            Vertices.Clear();
            Indices.Clear();

            List<CustomVertex.PositionNormalTextured> tmp_Vertices;
            IEngine.EngineInstance.LoadMeshFromFile(MeshFileName, out tmp_Vertices, out Indices);
            //IEngine.EngineInstance.CreateMesh(MeshFileName, new Vector3(0,0,0));
            Matrix scale = Matrix.Scaling(Scale.X, Scale.Y, Scale.Z);
            Matrix rotate = Matrix.RotationZ(((float)Math.PI / (float)180)*(float)Rotation.Z);
            Matrix translation = Matrix.Translation(Position);

            for (int i = 0; i < tmp_Vertices.Count; ++i)
            {
                Vector3 vec = new Vector3(tmp_Vertices[i].X, tmp_Vertices[i].Y, tmp_Vertices[i].Z);
                vec.TransformCoordinate(rotate);
                vec.TransformCoordinate(scale);
                vec.TransformCoordinate(translation);
                
                Vertices.Add(new CustomVertex.PositionNormalTextured()
                {
                    X = vec.X,
                    Y = vec.Y,
                    Z = vec.Z,

                    Tu = tmp_Vertices[i].Tu,
                    Tv = tmp_Vertices[i].Tv,
                });
            }

            if (Indices.Count == 0 || Vertices.Count == 0)
                return;

            MyMesh = new Mesh(Indices.Count / 3, Vertices.Count, MeshFlags.Managed | MeshFlags.Use32Bit, CustomVertex.PositionNormalTextured.Format, Device);
            MyMesh.IndexBuffer.SetData(Indices.ToArray(), 0, LockFlags.None);
            MyMesh.VertexBuffer.SetData(Vertices.ToArray(), 0, LockFlags.None);
            MyMesh.ComputeNormals();
            CollisionBox = new Engine.BoundingBox(this);
        }

        public virtual void Move(Vector3 new_position)
        {
            Position = new_position;
            ReloadMesh();
        }
    }
}
